//timerfd.cpp是一个定时器的使用示例，每隔3秒触发一次定时器超时，否则阻塞在read()

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/timerfd.h>

//我们使用linux库自带的定时器来实现一个3秒的定时功能
//linux定时器就是一个文件，每当过了这个时间OS会向对应的文件描述符写入8字节数据
//如果超时30次，间隔3秒，就会读取一个10
int main()
{
    //int timerfd_create(int clockid, int flags);
    //clockid是时间计算的基准值，我们使用系统开机的时间为基准值，避免因为用户更改系统时间而产生错误
    //flags是计时器的读取操作，0是阻塞操作
    //未到计时的时间，处于阻塞状态，但间隔一段时间(我们所计时的时长)系统就会向flags中写入1
    //返回一个文件操作符，计时器也是我们的文件
    int timerfd=timerfd_create(CLOCK_MONOTONIC,0); //我们创建一个定时器
    if(timerfd<0)
    {
        perror("timerfd_create error\n"); //创建计时器失败
        return -1;
    }

    //接下来我们要启动我们的计时器
    //int timerfd_settime(int fd, int flags,const struct itimerspec *new_value,struct itimerspec *old_value);
    //timerfd_create的返回值，flags默认为0，表示相对时间
    //struct itimerspec *new_value 设置的超时时间
    //struct itimerspec *old_value 接受定时器原来的超时时间
    //
    //struct itimerspec {
    //  struct timespec it_interval; /* 第⼀次之后的超时间隔时间 */
    //  struct timespec it_value; /* 第⼀次超时时间 */
    //};
    //struct timespec {
    //  time_t tv_sec; /* Seconds */
    //  long tv_nsec; /* Nanoseconds */
    //};
    
    //这里设置我们定时器的时间
    struct itimerspec itime;
    itime.it_value.tv_sec=1; //设置第一次的超时时间是1s
    itime.it_value.tv_nsec=0;

    itime.it_interval.tv_sec=1; //设置第一次超时后，每次间隔超时的时间
    itime.it_interval.tv_nsec=0;

    //填入参数，因为没有原来的定时器超时时间，所以设置为NULL
    timerfd_settime(timerfd,0,&itime,NULL);

    //每一秒读取timerfd的数据，看看有没有超时
    while(1)
    {
        uint64_t times; //每次超时，系统都要读取8字节的数据到timerfd中
        int ret=read(timerfd,&times,8); //从timerfd中读取数据放入times，没有数据读入就会阻塞，直到数据读入
        if(ret<0)
        {
            perror("read error\n");
            return -1;
        }
        printf("超时了，距离上一次超时了%ld次\n",times);
    }

    close(timerfd); //关闭定时器
    return 0;
}